import classNamesFn from 'classnames';
import KeyCode from 'rc-util/lib/KeyCode';
import React, { useEffect, useId, useRef } from 'react';
import { TPortalParams, YmDialogProps } from '../interface';
import Content from './Content';
import Mask from './Mask';

type IDialogChildProps = YmDialogProps &
  TPortalParams & {
    prefixCls: string;
  };

const Dialog: React.FC<IDialogChildProps> = (props) => {
  const {
    open,
    scrollLocker,
    afterClose,
    maskClosable = true,
    onClose,
    keyboard = true,
    prefixCls,
    rootClassName,
    mask = true,
    zIndex,
    classNames,
    styles,
    centered = true,
    ...restProps
  } = props;
  const ariaId = useId(); //这里用于无障碍阅读，详见react官网
  const { mask: maskClassName, wrapper: wrapClassName } = classNames || {};
  const { mask: maskStyle, wrapper: wrapStyle } = styles || {};
  const [animatedVisible, setAnimatedVisible] = React.useState(open);
  const wrapperRef = useRef<HTMLDivElement>(null);

  // 右上角关闭按钮、onWrapperClick 控制的是open --- open控制 Mask CSSMotion -- onVisibleChanged(onDialogVisibleChanged) 控制 animatedVisible -- animatedVisible 控制  rc-dialog-warp 的显影和DialogWrap.tsx 是否return null
  // 这样就可以实现从子组件到父组件从下往上一层一层display:'none'/卸载

  useEffect(() => {
    if (open) {
      setAnimatedVisible(true);
    }
    return () => {};
  }, [open]);

  useEffect(() => {
    if (animatedVisible) {
      scrollLocker.lock();
      if (wrapperRef.current && wrapperRef.current.style.display === 'block') {
        wrapperRef.current &&
          wrapperRef.current?.focus({ preventScroll: true }); //自动聚焦,用于esc键关闭dialog
      }
    } else {
      scrollLocker.unLock(); //如果不是点击关闭按钮，而是外部 open = false 路径来的呢？
    }
    // return () => { wrapperRef.current?.blur();};
  }, [animatedVisible, wrapperRef.current]);

  // ========================= Events =========================
  function onDialogVisibleChanged(newVisible: boolean) {
    // console.log('--onDialogVisibleChanged--newVisible---:', newVisible);
    if (newVisible) {
      //dialog打开时
    } else {
      //关闭

      // Clean up scroll bar & focus back
      setAnimatedVisible(false);

      // Trigger afterClose only when change visible from true to false
      if (animatedVisible) {
        afterClose?.();
      }
    }
  }

  function onInternalClose(e: React.SyntheticEvent) {
    onClose?.(e);
  }

  // >>> Content, onContentMouseDown、onContentMouseUp 都是由Panel触发的
  // Panel 区域click时做标记
  const contentClickRef = useRef(false);
  const contentTimeoutRef = useRef<NodeJS.Timeout>();

  const onContentMouseDown: React.MouseEventHandler = () => {
    clearTimeout(contentTimeoutRef.current);
    contentClickRef.current = true;
  };

  const onContentMouseUp: React.MouseEventHandler = () => {
    contentTimeoutRef.current = setTimeout(() => {
      contentClickRef.current = false;
    });
  };

  // >>> 点击 Wrapper
  const onWrapperClick = (e: React.SyntheticEvent) => {
    if (!maskClosable) return;
    if (contentClickRef.current) {
      contentClickRef.current = false;
    } else if (wrapperRef.current === e.target) {
      //e.target:事件触发对象
      onInternalClose(e);
    }
  };

  //esc键退出(只有当前dom节点/子节点 元素.focus()了，键盘事件才能触发)
  function onWrapperKeyDown(e: React.KeyboardEvent<HTMLDivElement>) {
    if (keyboard && e.keyCode === KeyCode.ESC) {
      //27
      e.stopPropagation();
      onInternalClose(e);
    }
  }

  useEffect(
    () => () => {
      clearTimeout(contentTimeoutRef.current);
    },
    [],
  );

  return (
    <div
      className={classNamesFn(`${prefixCls}-root`, rootClassName)}
      style={{}}
    >
      <Mask
        prefixCls={prefixCls}
        open={mask && open}
        motionName={`${prefixCls}-fade`} //'rc-dialog-fade'
        className={maskClassName}
        style={{
          zIndex,
          ...maskStyle,
        }}
      />
      <div
        tabIndex={-1}
        onKeyDown={onWrapperKeyDown}
        className={classNamesFn(`${prefixCls}-wrapper`, wrapClassName, {
          [`${prefixCls}-centered`]: !!centered,
        })} //rc-dialog-warp center
        ref={wrapperRef}
        onClick={onWrapperClick}
        style={{
          zIndex,
          ...wrapStyle,
          display: !animatedVisible ? 'none' : 'block',
        }}
      >
        <Content
          {...restProps}
          prefixCls={prefixCls}
          ariaId={ariaId}
          open={open}
          classNames={classNames}
          styles={styles}
          motionName={`${prefixCls}-zoom`}
          onClose={onInternalClose}
          onVisibleChanged={onDialogVisibleChanged}
          onMouseDown={onContentMouseDown}
          onMouseUp={onContentMouseUp}
        />
      </div>
    </div>
  );
};

export default Dialog;
